#pragma once 
#include "online.hpp"
#include "Util.hpp"
#include"log.hpp"
typedef enum { LOGIN,UNLOGIN} ss_statu;
class session
{
    private:
        uint64_t _ssid;//session内部标识符
        uint64_t _uid;//用户id
        ss_statu _statu;//用户状态信息
        websocketsvr::timer_ptr _tp;//session关联的定时器
    public:
        session(uint64_t ssid)
        :_ssid(ssid)
        ,_statu(UNLOGIN)
        {
            LOG(DEBUG,"SESSION %p 被创建!!!\n",this);
        }
        ~session()
        {
            LOG(DEBUG,"SESSION %p 被释放!!!\n",this);
        }

        void set_statu(ss_statu statu)
        {
            _statu = statu;
        }
        void set_user(uint64_t uid)
        {
            _uid = uid;
        }
        uint64_t get_ssid()
        {
            return _ssid;
        }
        uint64_t get_user()
        {
            return _uid;
        }
        bool is_login()
        {
            return (_statu == LOGIN);
        }
        void set_timer(const websocketsvr::timer_ptr& tp)
        {
            _tp = tp;
        }
        websocketsvr::timer_ptr& get_timer()
        {   
            return _tp;
        }
};
//设置定时器间隔时间
#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
using session_ptr = std::shared_ptr<session>;
class session_manage
{
    private:
        uint64_t _next_ssid;//sessionID
        std::mutex _mutex;
        std::unordered_map<uint64_t,session_ptr> _session;//管理用户id和session对象之间的关系
        websocketsvr* _server;//指向web服务器的指针
    public:
        session_manage(websocketsvr* server)
        :_next_ssid(1)
        ,_server(server)
        {
            LOG(DEBUG,"session 管理器 创建成功！\n");
        }
        ~session_manage()
        {
            LOG(DEBUG,"session 管理器即将销毁!\n");
        }
        void append_session(const session_ptr& ssp)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _session.insert(std::make_pair(ssp->get_ssid(),ssp));
        }

        session_ptr create_session(uint64_t uid,ss_statu statu)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            //创建了一个session 和一个指向它的智能指针
            session_ptr ssp(new session(_next_ssid));
            ssp->set_statu(statu);
            _session.insert(std::make_pair(_next_ssid,ssp));
            _next_ssid++;
            return ssp;
        }

        session_ptr get_session_by_ssid(uint64_t ssid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _session.find(ssid);
            if(it == _session.end())
            {
                return session_ptr();
            }
            return it->second;
        }

        void set_session_expire_time(uint64_t ssid,int ms)
        {   
            //依赖于websocketpp的定时器来完成session生命周期的管理。
            // 登录之后，创建session，session需要在指定时间无通信后删除
            // 但是进入游戏大厅，或者游戏房间，这个session就应该永久存在
            // 等到退出游戏大厅，或者游戏房间，这个session应该被重新设置为临时，在长时间无通信后被删除
            session_ptr ssp = get_session_by_ssid(ssid);
            if(ssp.get() == nullptr)
            {
                return;
            }
            websocketsvr::timer_ptr tp = ssp->get_timer();
            if(tp.get() == nullptr && ms == SESSION_FOREVER)
            {
                // 1. 在session永久存在的情况下，设置永久存在
                return ;
            }
            else if(tp.get() == nullptr && ms != SESSION_FOREVER)
            {
                //2.  在session永久存在的情况下，设置指定时间之后被删除的定时任务
                //创建定时删除session任务
                websocketsvr::timer_ptr tmp_tp = _server->set_timer(ms,
                std::bind(&session_manage::remove_session,this,ssid));
                //设置入session内
                ssp->set_timer(tmp_tp);
            }
            else if(tp.get() != nullptr && ms == SESSION_FOREVER)
            {
                // 3. 在session设置了定时删除的情况下，将session设置为永久存在
                // 删除定时任务--- stready_timer删除定时任务会导致任务直接被执行
                tp->cancel();//因为这个取消定时任务并不是立即取消的
                //因此重新给session管理器中，添加一个session信息, 且添加的时候需要使用定时器，而不是立即添加
                ssp->set_timer(websocketsvr::timer_ptr());//将session关联的定时器设置为空
                _server->set_timer(0,std::bind(&session_manage::append_session,this,ssp));
            }
            else if(tp.get() != nullptr && ms != SESSION_FOREVER)
            {
                //4 在设置了定时删除的情况下,将session重置删除时间
                tp->cancel();//因为这个定时任务不是立即被取消的
                ssp->set_timer(websocketsvr::timer_ptr());
                _server->set_timer(0,std::bind(&session_manage::append_session,this,ssp));
                //重新给session设置定时销毁任务
                //创建定时删除任务
                websocketsvr::timer_ptr tmp_tp = _server->set_timer(ms,
                std::bind(&session_manage::remove_session,this,ssp->get_ssid()));
                //重新设置session关联的定时器
                ssp->set_timer(tmp_tp);
            }

        }
        void remove_session(uint64_t ssid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _session.erase(ssid);

        }
};